<?php

namespace app\common\service;

use think\facade\Db;

class AuthService
{
    // 用户id
    protected mixed $uid;

    // 应用名称
    protected mixed $appName;

    // 用户信息
    protected mixed $userInfo;

    // 用户角色id
    protected mixed $userAuthIds;

    // 用户菜单id
    protected mixed $userMenuIds;

    /**
     * 默认配置
     * @var array
     */
    protected array $config;


    /***
     * 构造方法
     * AuthService constructor.
     */
    public function __construct($uid = null, $appName = null)
    {
        $this->uid         = $uid;
        $this->appName     = $appName == "admin" ? "group" : $appName;
        $this->config      = [
                'user'      => $this->appName . '_user',      // 用户表
                'user_auth' => $this->appName . '_user_auth', // 用户角色表
                'auth'      => $this->appName . '_auth',      // 角色表
                'auth_menu' => $this->appName . '_auth_menu', // 目录-菜单-权限-节点表
                'menu'      => $this->appName . '_menu',      // 菜单表
        ];
        $this->userInfo    = $this->getUserInfo();
        $this->userAuthIds = $this->getUserAuths();
        $this->userMenuIds = $this->getUserMenus();
        return $this;
    }

    /**
     * 获取当前节点
     * @return string
     */
    public function getCurrentNode(): string
    {
        return $this->parseNodeStr(request()->controller() . '/' . request()->action());
    }

    /**
     * 获取用户信息
     */
    public function getUserInfo()
    {
        return Db::name($this->config['user'])
                 ->where('id', $this->uid)
                 ->find();
    }

    /**
     * 检测检测权限
     */
    public function checkAuth($menuId = null, $href = null): bool
    {

        // 判断是否为超级管理员
        if ($this->userInfo['is_super'] == 1) {
            return true;
        }
        // 判断该用用是否拥有菜单权限
        if ($menuId && in_array($menuId, $this->userMenuIds)) return true;
        return false;
    }

    /**
     * 获取用户权限
     * @return array
     */
    private function getUserAuths(): array
    {
        return Db::name($this->config['user_auth'])
                 ->where("{$this->appName}_user_id", $this->uid)
                 ->column("{$this->appName}_auth_id");
    }

    /**
     * 获取用户菜单
     * @return array
     */
    public function getUserMenus(): array
    {
        return Db::name($this->config['auth_menu'])
                 ->where("{$this->appName}_auth_id", 'in', $this->userAuthIds)
                 ->column("{$this->appName}_menu_id");
    }

    /**
     * 检测菜单节点权限
     */
    public function checkNode($node = null): bool
    {
        // 判断是否为超级管理员
        if ( $this->userInfo['is_super'] == 1 ) {
            return true;
        }

        // 上传暂时不校验权限
        if( $node == 'upload/upload' ) {
            return true;
        }

        if (in_array($node, $this->getUserNode())) {
            return true;
        }
        return false;
    }

    /**
     * 获取所有菜单节点列表
     */
    public function getAuthMenuList($id, $authId): mixed
    {
        $checkMenuList = [];
        if (!empty($authId)) {
            //获取角色选中的权限菜单节点列表,过滤删除的菜单
            $checkMenuList = Db::name($this->config['auth_menu'])->where("{$this->appName}_auth_id", $authId)
                               ->column($this->appName . '_menu_id');
        }
        //获取所有菜单节点列表
        $menuList = Db::name($this->config['menu'])->field('id,pid,href,title,menu_type')
                      ->where("{$this->appName}_id", $id)
                      ->where('status', 1)
                      ->where('delete_time', null)
                      ->order('sort desc')
                      ->select()
                      ->toArray();
        //递归构建树形结构
        return $this->buildChildNode(0, $menuList, $checkMenuList);
    }

    /**
     * 递归构建树形结构
     * @param $pid
     * @param $menuList
     * @param $checkMenuList
     * @return mixed
     */
    public function buildChildNode($pid, $menuList, $checkMenuList): mixed
    {
        $newMenuList = [];
        foreach ($menuList as $v) {
            if ($v['pid'] == $pid) {
                //                $v            = array_merge($v, ['spread' => true]);
                $v['checked'] = in_array($v['id'], $checkMenuList) ? true : false;
                $v['title']   = "{$v['title']}";
                $child        = $this->buildChildNode($v['id'], $menuList, $checkMenuList);
                if (!empty($child)) {
                    $v['children'] = $child;
                }
                $newMenuList[] = $v;
            }
        }
        return $newMenuList;
    }

    /**
     * 获取用户节点
     */
    public function getUserNode(): array
    {
        $nodeList = [];
        if (!empty($this->userInfo) && !empty($this->userAuthIds)) {
            $buildAuthMenuSql = Db::name($this->config['auth_menu'])
                                  ->distinct(true)
                                  ->whereIn("{$this->appName}_auth_id", $this->userAuthIds)
                                  ->field("{$this->appName}_menu_id")
                                  ->buildSql(true);
            $nodeList         = Db::name($this->config["menu"])
                                  ->distinct(true)
                                  ->where("id IN {$buildAuthMenuSql}")
                                  ->where("api", "<>", '')
                                  ->column('api');
        }
        return $nodeList;
    }

    /**
     * 驼峰转下划线规则
     * @param string $node
     * @return string
     */
    public function parseNodeStr(string $node): string
    {
        $array = explode('/', $node);
        foreach ($array as $key => $val) {
            $val = explode('.', $val);
            foreach ($val as &$vo) {
                $vo = \think\helper\Str::snake(lcfirst($vo));
            }
            $val         = implode('.', $val);
            $array[$key] = $val;
        }
        return implode('/', $array);
    }


}